package org.domain.pseample.session;

import java.io.IOException;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.servlet.sip.SipServletRequest;
import javax.servlet.sip.SipServletResponse;
import javax.servlet.sip.SipSession;
import javax.servlet.sip.SipURI;

import org.jboss.aspects.Current;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.log.Log;

import org.jboss.seam.security.Credentials;
import org.jboss.seam.security.Identity;
import org.mobicents.mscontrol.MsConnection;
import org.mobicents.mscontrol.MsConnectionEvent;
import org.mobicents.mscontrol.MsLink;
import org.mobicents.mscontrol.MsLinkEvent;
import org.mobicents.mscontrol.MsLinkMode;
import org.mobicents.servlet.sip.seam.entrypoint.media.MediaController;
import org.mobicents.servlet.sip.seam.entrypoint.media.MediaEvent;
import org.mobicents.servlet.sip.seam.media.framework.IVRHelper;
import org.mobicents.servlet.sip.seam.media.framework.MediaEventDispatcher;
import org.mobicents.servlet.sip.seam.media.framework.MediaSessionStore;

@Name("mediaFrameworkDemo")
@Stateless
public class MediaHandler {
	@Logger
	Log log;
	@In
	MediaController mediaController;
	@In
	SipSession sipSession;
	@In
	MediaSessionStore mediaSessionStore;
	@In
	IVRHelper ivrHelper;
	@In
	MediaEventDispatcher mediaEventDispatcher;

	@In(scope = ScopeType.APPLICATION, required = false)
	@Out(scope = ScopeType.APPLICATION, required = false)
	String conferenceEndpointName;

	public static final String IVR_JNDI_NAME = "media/trunk/IVR/$";
	private String user;

	// private final String announcement =
	// "file:///home/zubeen/Prism/workspace/seample/audio/everyone.wav";

	@Observer("INVITE")
	public void doInvite(SipServletRequest request) throws Exception {
		// Extract SDP from the SIp message
		String sdp = new String((byte[]) request.getContent());

		// Tell the other side to ring (status 180)
		request.createResponse(SipServletResponse.SC_RINGING).send();

		user = request.getFrom().getDisplayName();
		if (user == null && request.getFrom().getURI() instanceof SipURI) {
			user = ((SipURI) request.getFrom().getURI()).getUser();
		}

		MapInstance mapInstance = MapInstanceManager.instance().getMapInstance(
				user);

		if (mapInstance == null) {
			log.info(user + " tried to connect");
			request.createResponse(SipServletResponse.SC_DECLINE).send();

		}

		else {

			// Store the INVITE request in the sip session
			sipSession.setAttribute("inviteRequest", request);
			sipSession.setAttribute("username", user);
			// If this is the first INVITE in the app, then we must start a new
			// conference
			// if (conferenceEndpointName == null)
			conferenceEndpointName = "media/trunk/PacketRelay/$";

			// Create a connection between the UA and the conference endpoint
			MsConnection msConnection = mediaController
					.createConnection(conferenceEndpointName);
			msConnection.modify("$", sdp); // also updates the SDP in Media
			// Server to match capabilities of
			// UA
			sipSession.setAttribute("msConnection", msConnection);
		}
	}

	@Observer("storeConnectionOpen")
	public void doConnectionOpen(MsConnectionEvent event) throws IOException {
		// Save this connection where the framework can read it
		// mediaSessionStore.setMsConnection(event.getConnection());// This is
		// done automatically in STF 2.0

		// The conference endpoint is now assiged after we are connected, so
		// save it too
		conferenceEndpointName = event.getConnection().getEndpoint()
				.getLocalName();

		// Recall the INVITE request that we saved in doInvite
		SipServletRequest request = (SipServletRequest) sipSession
				.getAttribute("inviteRequest");

		MsConnection msConnection = (MsConnection) sipSession
				.getAttribute("msConnection");
		MsLink ivrlink = mediaController.createLink(MsLinkMode.FULL_DUPLEX);
		log.info("msconnection " + msConnection);
		log.info("msConnection.getEndpoint() " + msConnection.getEndpoint());
		ivrlink.join(IVR_JNDI_NAME, msConnection.getEndpoint().getLocalName());
		sipSession.setAttribute("ivrlink", ivrlink);
		log.info("linking " + msConnection.getEndpoint().getLocalName()
				+ "to IVR");
		// Make OK (status 200) to tell the other side that the call is
		// established
		SipServletResponse response = request
				.createResponse(SipServletResponse.SC_OK);

		// Put the SDP inside the OK message to tell what codecs and so on we
		// agree with
		response.setContent(event.getConnection().getLocalDescriptor(),
				"application/sdp");

		// Now actually send the message
		response.send();

		// And start listening for DTMF signals
		ivrHelper.detectDtmf();
	}

	@SuppressWarnings("deprecation")
	@Observer("DTMF")
	public void dtmf(String button) {
		System.out.println("DTMF: " + button);

		/* retrieves the key pressed */

		Integer dtmf = Integer.parseInt(button);
		// If the other side presses the button "0" stop the playback
		if (dtmf == 0) {
			ivrHelper.endAll();
		} else {

			ConferenceCenter conferenceCenter = ConferenceCenterManager
					.instance().getConferenceCenter(dtmf);

			/*
			 * checking either the current user is authorized to join the
			 * conference or not
			 */
			String username = (String)sipSession.getAttribute("username");
			log.info("Username mediahandler" + username);
			log.info("Administrator" + conferenceCenter.getAdmin());
			log.info("user exists "
					+ conferenceCenter.checkConferenceUser(username));
			if (conferenceCenter.checkConferenceUser(username)) {

				log.info("connecting to conference");
				// SipServletRequest request = (SipServletRequest)
				// sipSession.getAttribute("inviteRequest");
				MsConnection msConnection = (MsConnection) sipSession
						.getAttribute("msConnection");// can be got from
				// mediaSession store?
				MsLink ivrlink = (MsLink) sipSession.getAttribute("ivrlink");
				ivrlink.release();
				// String sdp;
				// sdp = new String((byte[]) request.getContent());
				// msConnection.modify("$",sdp);
				MsLink conflink = mediaController
						.createLink(MsLinkMode.FULL_DUPLEX);
				log.info("End Point "
						+ conferenceCenter.getConferenceEndPoint());
				log.info("PR " + msConnection.getEndpoint().getLocalName());
				ivrlink.join(conferenceCenter.getConferenceEndPoint(),
						msConnection.getEndpoint().getLocalName());
				sipSession.setAttribute("conflink", conflink);
				log.info("linking " + msConnection.getEndpoint().getLocalName()
						+ "to PR");
			}
		} /*
		 * else { // otherwise play announcement
		 * ivrHelper.playAnnouncementWithDtmf(announcement); }
		 */
		// Also log the DTMF buttons pressed so far in this session
		log.info("Current DTMF Stack for the SIP Session: "
				+ mediaEventDispatcher.getDtmfArchive(sipSession));
	}

	@Observer( { "BYE" })
	public void doBye(SipServletRequest request) throws Exception {
		request.createResponse(200).send();
		// And clean up the connections
		// MsConnection connection = mediaSessionStore.getMsConnection();
		MsLink ivrlink = (MsLink) sipSession.getAttribute("ivrlink");
		if (ivrlink != null)
			ivrlink.release();
		MsLink conflink = (MsLink) sipSession.getAttribute("conflink");
		if (conflink != null)
			conflink.release();
		MsConnection msConnection = (MsConnection) sipSession
				.getAttribute("msConnection");// can be got from mediaSession
		// store?
		msConnection.release();
	}

	@Observer("REGISTER")
	public void doRegister(SipServletRequest request) throws Exception {
		request.createResponse(200).send();
	}

	@Observer("mediaEvent")
	public void mediaEvent(MediaEvent mediaEvent) {
	}

	@Observer("connectionCreated")
	public void doConnectionEvent1(MsConnectionEvent event) throws IOException {
		System.out.println("doConnOpen");
	
	}

	@Observer("connectionDisconnected")
	public void doConnectionEvent2(MsConnectionEvent connectionEvent) {
	}

	@Observer("connectionFailed")
	public void doConnectionEvent3(MsConnectionEvent connectionEvent) {
		log.error("connection failed ");
		try {
			SipServletRequest request = (SipServletRequest) sipSession
					.getAttribute("inviteRequest");
			request.createResponse(SipServletResponse.SC_SERVER_INTERNAL_ERROR)
					.send();
		} catch (IOException e) {
			log.error("Exception in sending the error response", e);
		}

	}

	@Observer("connectionHalfOpen")
	public void doConnectionEvent4(MsConnectionEvent connectionEvent) {
	}

	@Observer("connectionModeRecvOnly")
	public void doConnectionEvent5(MsConnectionEvent connectionEvent) {
	}

	@Observer("connectionOpen")
	public void doConnectionEvent6(MsConnectionEvent connectionEvent) {
		log.info("connection ope request" + connectionEvent);

	}

	@Observer("connectionModeSendRecv")
	public void doConnectionEvent7(MsConnectionEvent connectionEvent) {
	}

	@Observer("connectionModeSendOnly")
	public void doConnectionEvent8(MsConnectionEvent connectionEvent) {
	}

	// Media Link Events

	@Observer("linkConnected")
	public void doLinkEvent1(MsLinkEvent linkEvent) {
		ivrHelper.detectDtmf();
		log.info("link connected " + linkEvent.getMessage());
	}

	@Observer("linkCreated")
	public void doLinkEvent2(MsLinkEvent linkEvent) {
		ivrHelper.detectDtmf();
		log.info("PR-IVR link created " + linkEvent);
	}

	@Observer("linkDisconnected")
	public void doLinkEvent3(MsLinkEvent linkEvent) {
	}

	@Observer("linkFailed")
	public void doLinkEvent4(MsLinkEvent linkEvent) {
		log.info("link failed");
	}

	@Observer("modeFullDuplex")
	public void doLinkEvent5(MsLinkEvent linkEvent) {
	}

	@Observer("modeHalfDuplex")
	public void doLinkEvent6(MsLinkEvent linkEvent) {
	}

	// Notification events (for DTMF and others)

	@Observer("mediaEvent")
	public void doMediaEvent(MediaEvent mediaEvent) {
	}

	@Observer("announcementComplete")
	// Fired when the announcement in the current SipSession context is complete
	public void doAnnouncementComplete(MediaEvent event) {
	}

	@Observer("announcementFailed")
	// Fired when the announcement in the current SipSession context has failed
	public void doAnnouncementFailed(MediaEvent event) {
	}

	@Observer("audioFailed")
	// Fired when there is a problem with audio
	public void doAudioFailed(MediaEvent event) {
	}

}